package eval

import (
	"bytes"
	"fmt"
)

func Format(e Expr) string {
	var buf bytes.Buffer
	write(&buf, e)
	return buf.String()
}

func write(buf *bytes.Buffer, e Expr) {
	switch e := e.(type) {
	case literal:
		fmt.Fprintf(buf, "%g", e)
	case Var:
		fmt.Fprintf(buf, "%s", e)
	case unary:
		fmt.Fprintf(buf, "(%c", e.op)
		write(buf, e.x)
		fmt.Fprintf(buf, ")")
	case binary:
		fmt.Fprintf(buf, "(")
		write(buf, e.x)
		fmt.Fprintf(buf, " %c ", e.op)
		write(buf, e.y)
		fmt.Fprintf(buf, ")")
	case call:
		fmt.Fprintf(buf, "%s(", e.fn)
		for i, arg := range e.args {
			if i > 0 {
				fmt.Fprintf(buf, ", ")
			}
			write(buf, arg)
		}
		fmt.Fprintf(buf, ")")
	default:
		panic(fmt.Sprintf("unknown expr: %T", e))
	}
}
